package com.lensyn.generator.plugins;

import com.lensyn.generator.domain.MsgKey;
import com.lensyn.generator.handler.*;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.TopLevelClass;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.*;

/**
 * 利用插件，产生DTO，Service，Controller 基本上改查
 * @author xiaob@lensysn.com
 * @date 2016/12/20
 * @see {@link DefaultHandlerAdapter}
 * @see GenerateController
 * @see GenerateDto
 * @see GenerateServiceInterface
 * @see GenerateServiceImpl
 */
public class CUIDPlugin extends PluginAdapter {

    /**
     * 基本包名
     */
    final String KEY_PACKAGE_NAME = "package.name";
    /**
     * 默认实现
     * @see {@link DefaultHandlerAdapter}
     */
    final String KEY_RUNTIME_CLASS = "runtime";  //com.lensyn.generator.handler.DefaultHandlerAdapter

    /**
     * 模块名称映射，值映射表明的头部，<br/>
     * 用模块划分service，controller等，<br/>
     * 例如表：el_table  ,可以映射el为 add.name,
     */
    final String KEY_MODULE_MAPPING = "module.mapping";


    /**
     * controller ,service,dto 生成处理类
     */
    ControllerNameHandler controllerNameHandler;
    ServiceNameHandler serviceNameHandler;
    DtoNameHandler dtoNameHandler;

    EntityMetaHandler entityMetaHandler;


    Set<MsgKey> msgKeys = new HashSet<MsgKey>();
    Properties msgProperties = new Properties();

    public CUIDPlugin() {
        super();
    }

    @Override
    public void setProperties(Properties properties) {
        super.setProperties(properties);

        String defaultRuntime = properties.getProperty(KEY_RUNTIME_CLASS, "com.lensyn.generator.handler.DefaultHandlerAdapter");

        serviceNameHandler = (ServiceNameHandler) runtime(properties.getProperty("service.runtime", defaultRuntime));
        dtoNameHandler = (DtoNameHandler) runtime(properties.getProperty("dto.runtime", defaultRuntime));
        controllerNameHandler = (ControllerNameHandler) runtime(properties.getProperty("controller.runtime", defaultRuntime));
        entityMetaHandler = (EntityMetaHandler)runtime(properties.getProperty("entity.meta.runtime", defaultRuntime));

        Properties moduleMapping = new Properties();
        try {
            moduleMapping.load(this.getClass().getClassLoader().getResourceAsStream(properties.getProperty(KEY_MODULE_MAPPING)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        serviceNameHandler.setModuleMapping(moduleMapping);
        dtoNameHandler.setModuleMapping(moduleMapping);
        controllerNameHandler.setModuleMapping(moduleMapping);
        entityMetaHandler.setModuleMapping(moduleMapping);

        String basePackage = getProperties().getProperty(KEY_PACKAGE_NAME);
        serviceNameHandler.setPackageName(basePackage);
        dtoNameHandler.setPackageName(basePackage);
        controllerNameHandler.setPackageName(basePackage);
        entityMetaHandler.setPackageName(basePackage);
        ;
    }

    Object runtime(String className) {


        try {
            Class cls = Class.forName(className);


            return cls.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {

        List<GeneratedJavaFile> dtoFiles = new ArrayList<GeneratedJavaFile>();

        //dto
        TopLevelClass dtoClass = generateDto(introspectedTable);
        dtoFiles.add(generatedJavaFile(dtoClass));

        //service interface
        Interface serviceInterface = generateServiceInterface(introspectedTable, dtoClass);
        dtoFiles.add(generatedJavaFile(serviceInterface));

        //service interfaceImpl
        TopLevelClass serviceInterfaceImpl = generateServiceInterfaceImpl(introspectedTable, dtoClass, serviceInterface);
        dtoFiles.add(generatedJavaFile(serviceInterfaceImpl));

        //controller
        TopLevelClass controller = generateController(introspectedTable, dtoClass, serviceInterface);
        dtoFiles.add(generatedJavaFile(controller));

        //gen table metas
        TopLevelClass entityMeta = generateEntityMeta(introspectedTable);
        dtoFiles.add(generatedJavaFile(entityMeta));


        processMsgKeys();

        return dtoFiles;
    }

    private TopLevelClass generateEntityMeta(IntrospectedTable introspectedTable) {
        GenerateEntityMeta meta = new GenerateEntityMeta(introspectedTable,entityMetaHandler);
        return meta.generate();
    }


    private TopLevelClass generateController(IntrospectedTable introspectedTable, TopLevelClass dtoClass, Interface serviceInterface) {
        GenerateController controller = new GenerateController(introspectedTable, dtoClass, controllerNameHandler, serviceInterface);
        return controller.generate();
    }


    /**
     * @param introspectedTable
     * @param dtoClass
     * @param serviceInterface
     * @return
     */
    private TopLevelClass generateServiceInterfaceImpl(IntrospectedTable introspectedTable, TopLevelClass dtoClass, Interface serviceInterface) {

        GenerateServiceImpl serviceImpl = new GenerateServiceImpl(introspectedTable, dtoClass, serviceNameHandler, serviceInterface);

        return serviceImpl.generateImpl();
    }

    /**
     * 产生Interface
     *
     * @param introspectedTable
     * @param dtoClass
     * @return
     */
    private Interface generateServiceInterface(IntrospectedTable introspectedTable, TopLevelClass dtoClass) {
        GenerateServiceInterface generateServiceInterface =
                new GenerateServiceInterface(introspectedTable, dtoClass, serviceNameHandler);
        return generateServiceInterface.generate();
    }

    /**
     * gen Dto
     *
     * @param introspectedTable
     * @return
     */
    private TopLevelClass generateDto(IntrospectedTable introspectedTable) {
        GenerateDto generateDto = new GenerateDto(introspectedTable, dtoNameHandler);

        TopLevelClass levelClass = generateDto.generate();

        Set<MsgKey> keys = generateDto.getMsgKeys();


        msgKeys.addAll(keys);

        return levelClass;
    }

    protected GeneratedJavaFile generatedJavaFile(CompilationUnit compilationUnit) {

        GeneratedJavaFile gjf = new GeneratedJavaFile(compilationUnit,
                context.getJavaClientGeneratorConfiguration().getTargetProject(),
                context.getProperty("javaFileEncoding"),
                context.getJavaFormatter());

        return gjf;
    }


    void processMsgKeys(){

        if(msgKeys.isEmpty()){
           return;
        }

        for(MsgKey msgKey:msgKeys){
            msgProperties.put(msgKey.getKey(),msgKey.getMsg());
        }

      String targetProject =   context.getJavaClientGeneratorConfiguration().getTargetProject();

        File file = new File(targetProject,"ValidationMessages.properties");

        try {
            FileOutputStream fos = new FileOutputStream(file, false);
            OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
            msgProperties.store(osw,"");
        }catch (Exception e){
            e.printStackTrace();
        }


    }


    public boolean validate(List<String> warnings) {
        return true;
    }
}
